package com.yswy.common.wxOrder.V2;

import com.github.wxpay.sdk.WXPay;
import com.github.wxpay.sdk.WXPayUtil;
import com.yswy.common.utils.DateUtils;
import com.yswy.common.utils.IpUtils;
import com.yswy.common.utils.JsonMapper;
import com.yswy.common.utils.StringUtils;
import com.yswy.common.wxOrder.V2.wxconfig.WxConstant;
import com.yswy.common.wxOrder.V2.wxconfig.WxPayConfig;
import lombok.extern.slf4j.Slf4j;

import com.wechat.pay.java.core.Config;
import com.wechat.pay.java.core.RSAAutoCertificateConfig;
import com.wechat.pay.java.service.transferbatch.model.InitiateBatchTransferRequest;
import com.wechat.pay.java.service.transferbatch.model.InitiateBatchTransferResponse;
import com.wechat.pay.java.service.transferbatch.model.TransferDetailInput;


import java.math.BigDecimal;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.*;

@Slf4j
public class WechatNotes {
    /**
     * app支付
     * @param wxPayConfig 微信配置文件
     * @param outTradeNo 订单号
     * @param amount 金额
     * @param body  商品描述
     * @return
     */
    public String appPay(WxPayConfig wxPayConfig , String outTradeNo, String amount, String body) {
        WXPay wxPay;
        try {
            // 初始化微信支付
            wxPay = new WXPay(wxPayConfig);
        } catch (Exception e) {
            log.info("微信支付-APP下单异常 -初始化微信支付错误：{}", e.getMessage());
            e.printStackTrace();
            throw new IllegalArgumentException("微信支付-APP下单失败");
        }
        // 请求参数
        Map<String, String> requestData = requestData(body,  outTradeNo, amount, "APP" , wxPayConfig);
        // 应用appId
        requestData.put("appid", wxPayConfig.getAppID());
        // 商户号
        requestData.put("mch_id", wxPayConfig.getMchID());
        // 签名
        String sign;
        // 返回结果
        Map<String, String> resultMap;
        try {
            // 算法签名
            sign = WXPayUtil.generateSignature(requestData, wxPayConfig.getKey());
            requestData.put("sign", sign);
            // 发起支付下单
            resultMap = wxPay.unifiedOrder(requestData);
        } catch (Exception e) {
            log.info("微信支付-APP下单异常：{}", e.getMessage());
            e.printStackTrace();
            throw new IllegalArgumentException("微信支付-APP下单失败");
        }
        log.info("微信支付-APP下单返回结果:{}", resultMap);
        if (resultMap.containsKey(WxConstant.WX_PAY_RETURN_CODE) && resultMap.containsKey(WxConstant.WX_PAY_RESULT_CODE)) {
            // 返回码
            String returnCode = resultMap.get("return_code");
            // 结果码
            String resultCode = resultMap.get("result_code");
            // 对比返回码和结果码
            if (WxConstant.SUCCESS.equals(resultCode) && WxConstant.SUCCESS.equals(returnCode)) {
                // 填写APP调用JSON参数
                Map<String, String> dataMap = new LinkedHashMap<>();
                dataMap.put("appid", resultMap.get("appid"));
                dataMap.put("noncestr", resultMap.get("nonce_str"));
                dataMap.put("prepayid", resultMap.get("prepay_id"));
                dataMap.put("partnerid", resultMap.get("mch_id"));
                dataMap.put("package", "Sign=WXPay");
                dataMap.put("timestamp", String.valueOf(System.currentTimeMillis() / 1000));
                String paySign;
                try {
                    // 二次签名
                    paySign = WXPayUtil.generateSignature(dataMap, wxPayConfig.getKey());
                } catch (Exception e) {
                    log.info("微信支付-APP二次签名错误:{}", e.getMessage());
                    e.printStackTrace();
                    throw new IllegalArgumentException("微信支付-APP二次签名错误");
                }
                dataMap.put("sign", paySign);
                log.info("微信支付-APP下单成功,APP接口返回拼接结果:{}", dataMap);
                return JsonMapper.toJson(dataMap);
            } else {
                log.info("微信支付-APP下单失败,返回参数:{}", JsonMapper.toJson(resultMap));
                throw new IllegalArgumentException("微信支付-APP下单失败");
            }
        } else {
            log.info("微信支付 -APP下单失败,返回参数:{}", JsonMapper.toJson(resultMap));
            throw new IllegalArgumentException("微信支付-APP下单失败");
        }
    }









    public RetuenPayOrder appletPay(WxPayConfig wxPayConfig, CreateOrderVo createOrderVo , String ip , String phone
            , String openId, Integer isRetention , Integer useLocation) {
        if (StringUtils.isEmpty(openId)){
            throw new IllegalArgumentException("微信支付 -公众号(小程序)下单失败");
        }
        WXPay wxPay;
        String outTradeNo = createOrderVo.getOrderId();
        String amount = createOrderVo.getAmount().toString();
        String body = createOrderVo.getSubject() ;
        try {
            // 初始化微信支付
            wxPay = new WXPay(wxPayConfig);
        } catch (Exception e) {
            log.info("微信支付 -公众号(小程序)下单异常 -初始化微信支付错误：{}", e.getMessage());
            e.printStackTrace();
            throw new IllegalArgumentException("微信支付 -公众号(小程序)下单失败");
        }
        // 请求参数
        Map<String, String> requestData = requestData(body, outTradeNo, amount, "JSAPI" , wxPayConfig);
        //openid
        requestData.put("openid", openId);
        // 签名
        String sign;
        // 返回结果
        Map<String, String> resultMap;
        try {
            // 算法签名
            sign = WXPayUtil.generateSignature(requestData, wxPayConfig.getKey());
            requestData.put("sign", sign);
            // 发起支付下单
            resultMap = wxPay.unifiedOrder(requestData);
        } catch (Exception e) {
            log.info("微信支付 -公众号(小程序)下单异常：{}", e.getMessage());
            e.printStackTrace();
            throw new IllegalArgumentException("微信支付 -公众号(小程序)下单失败");
        }
        log.info("微信支付 -公众号下(小程序)单返回结果:{}", resultMap);
        if (resultMap.containsKey(WxConstant.WX_PAY_RETURN_CODE) && resultMap.containsKey(WxConstant.WX_PAY_RESULT_CODE)) {
            // 返回码
            String returnCode = resultMap.get("return_code");
            // 结果码
            String resultCode = resultMap.get("result_code");
            // 对比返回码和结果码
            if (WxConstant.SUCCESS.equals(resultCode) && WxConstant.SUCCESS.equals(returnCode)) {
                // 填写小程序调用JSON参数
                Map<String, String> dataMap = new LinkedHashMap<>();
                dataMap.put("appId", resultMap.get("appid"));
                dataMap.put("nonceStr", resultMap.get("nonce_str"));
                dataMap.put("package", "prepay_id=" + resultMap.get("prepay_id"));
                dataMap.put("timeStamp", String.valueOf(System.currentTimeMillis() / 1000));
                dataMap.put("signType", "MD5");
                String paySign;
                try {
                    // 二次签名
                    paySign = WXPayUtil.generateSignature(dataMap, wxPayConfig.getKey());
                } catch (Exception e) {
                    log.info("微信支付 -公众号(小程序)二次签名错误:{}", e.getMessage());
                    e.printStackTrace();
                    throw new IllegalArgumentException("微信支付 -公众号(小程序)二次签名错误");
                }
                dataMap.put("sign", paySign);
                log.info("微信支付 -公众号(小程序)下单成功,接口返回拼接结果:{}", dataMap);


                String prepay_id = resultMap.get("prepay_id");
                dataMap.put("prepayId", prepay_id);
                RetuenPayOrder retuenPayOrder = new RetuenPayOrder();
                retuenPayOrder.setOrderId(outTradeNo);
                retuenPayOrder.setDownUrl(createOrderVo.getDownUrl());
                retuenPayOrder.setDataMap(dataMap);
                retuenPayOrder.setPayTerrace(2);
                retuenPayOrder.setAppId(wxPayConfig.getAppId());
                return retuenPayOrder ;
            } else {
                log.info("微信支付 -公众号(小程序)下单失败,返回参数:{}", JsonMapper.toJson(resultMap));
                throw new IllegalArgumentException("微信支付 -公众号(小程序)下单失败");
            }
        } else {
            log.info("微信支付 -公众号(小程序)下单失败,返回参数:{}", JsonMapper.toJson(resultMap));
            throw new IllegalArgumentException("微信支付 -公众号(小程序)下单失败");
        }
    }
    /**
     * @author bing
     * @param
     * @Description 微信h5下单
     * @date 2022/2/24 11:27
     * @return
     */
    public RetuenPayOrder wxH5Pay(WxPayConfig wxPayConfig,CreateOrderVo createOrderVo ,
                                  String ip , String phone, Integer isRetention , String  url) {

        WXPay wxPay;
        String amount = createOrderVo.getAmount().toString();
        String body = createOrderVo.getSubject() ;
        String outTradeNo = createOrderVo.getOrderId();
        try {
            // 初始化微信支付
            wxPay = new WXPay(wxPayConfig);
        } catch (Exception e) {
            log.info("微信支付 -h5下单异常 -初始化微信支付错误：{}", e.getMessage());
            e.printStackTrace();
            throw new IllegalArgumentException("微信支付 -h5下单失败");
        }
        // 请求参数
        Map<String, String> requestData = requestData(body, outTradeNo, amount, "MWEB" , wxPayConfig);
        // 应用appId
        requestData.put("appid", wxPayConfig.getAppID());
        // 商户号
        requestData.put("mch_id", wxPayConfig.getMchID());
        //商品详情
        requestData.put("detail","限时活动");
        //订单失效时间

        requestData.put("spbill_create_ip",ip);
        // 签名
        String sign;
        // 返回结果
        Map<String, String> resultMap;
        try {
            // 算法签名
            System.out.println(wxPayConfig.getKey());
            sign = WXPayUtil.generateSignature(requestData, wxPayConfig.getKey());
            System.out.println(sign);
            requestData.put("sign", sign);
            // 发起支付下单
            resultMap = wxPay.unifiedOrder(requestData);
        } catch (Exception e) {
            e.printStackTrace();
            log.info("微信支付 -h5下单异常：{}", e.getMessage());
            e.printStackTrace();
            throw new IllegalArgumentException("微信支付 -h5下单失败");
        }
        log.info("微信支付 -h5返回结果:{}", resultMap);
        if (resultMap.containsKey(WxConstant.WX_PAY_RETURN_CODE) && resultMap.containsKey(WxConstant.WX_PAY_RESULT_CODE)) {
            // 返回码
            String returnCode = resultMap.get("return_code");
            // 结果码
            String resultCode = resultMap.get("result_code");
            // 对比返回码和结果码
            if (WxConstant.SUCCESS.equals(resultCode) && WxConstant.SUCCESS.equals(returnCode)) {
                // 填写小程序调用JSON参数
                Map<String, String> dataMap = new LinkedHashMap<>();
                dataMap.put("appId", resultMap.get("appid"));
                dataMap.put("nonceStr", resultMap.get("nonce_str"));
                dataMap.put("package", "prepay_id=" + resultMap.get("prepay_id"));
                dataMap.put("timeStamp", String.valueOf(System.currentTimeMillis() / 1000));
                dataMap.put("signType", "MD5");
                String paySign;
                try {
                    // 二次签名
                    paySign = WXPayUtil.generateSignature(dataMap, wxPayConfig.getKey());
                } catch (Exception e) {
                    log.info("微信支付 -h5二次签名错误:{}", e.getMessage());
                    e.printStackTrace();
                    throw new IllegalArgumentException("微信支付 -小程序二次签名错误");
                }
                dataMap.put("sign", paySign);
                log.info("微信支付 -h5下单成功,接口返回拼接结果:{}", dataMap);

                String mweb_url = resultMap.get("mweb_url");
//                mweb_url +="&redirect_url="+url;
//                resultMap.put("mweb_url" , mweb_url);


//                WechatNotes notifyNotes = new WechatNotes();
//                notifyNotes.setPhone(phone);
//                notifyNotes.setOutTradeNo(outTradeNo);
//                notifyNotes.setResultCode(resultCode);
//                this.save(notifyNotes);

                RetuenPayOrder retuenPayOrder = new RetuenPayOrder();
                retuenPayOrder.setOrderId(outTradeNo);
                retuenPayOrder.setPayTerrace(1);
                retuenPayOrder.setDownUrl(createOrderVo.getDownUrl());
                retuenPayOrder.setTrademsg(mweb_url+"&redirect_url=" +URLEncoder.encode(createOrderVo.getDownUrl()));
                retuenPayOrder.setAppId(wxPayConfig.getAppId());
                return retuenPayOrder;
            } else {
                log.info("微信支付 -h5下单失败,返回参数:{}", JsonMapper.toJson(resultMap));
                throw new IllegalArgumentException("微信支付 -h5下单失败");
            }
        } else {
            log.info("微信支付 -h5下单失败,返回参数:{}", JsonMapper.toJson(resultMap));
            throw new IllegalArgumentException("微信支付 -h5下单失败");
        }
    }


    /**
     *扫码支付
     * @param wxPayConfig 微信配置
     * @param outTradeNo 订单号
     * @param amount 订单金额
     * @param body 订单描述
     * @return
     */
    public String nativePay(WxPayConfig wxPayConfig , String outTradeNo, String amount, String body) {
        WXPay wxPay;
        try {
            // 初始化微信支付
            wxPay = new WXPay(wxPayConfig);
        } catch (Exception e) {
            log.info("微信支付  -扫码支付下单异常 -初始化微信支付错误：{}", e.getMessage());
            e.printStackTrace();
            throw new IllegalArgumentException("微信支付  -扫码支付下单失败");
        }
        // 请求参数
        Map<String, String> requestData = requestData(body, outTradeNo, amount, "NATIVE" , wxPayConfig);
        // 签名
        String sign;
        // 返回结果
        Map<String, String> resultMap;
        try {
            // 算法签名
            sign = WXPayUtil.generateSignature(requestData, wxPayConfig.getKey());
            requestData.put("sign", sign);
            // 发起支付下单
            resultMap = wxPay.unifiedOrder(requestData);
        } catch (Exception e) {
            log.info("微信支付  -扫码支付下单异常：{}", e.getMessage());
            e.printStackTrace();
            throw new IllegalArgumentException("微信支付  -扫码支付下单失败");
        }
        log.info("微信支付  -扫码支付下单返回结果:{}", resultMap);
        if (resultMap.containsKey(WxConstant.WX_PAY_RETURN_CODE) && resultMap.containsKey(WxConstant.WX_PAY_RESULT_CODE)) {
            // 返回码
            String returnCode = resultMap.get("return_code");
            // 结果码
            String resultCode = resultMap.get("result_code");
            // 对比返回码和结果码
            if (WxConstant.SUCCESS.equals(resultCode) && WxConstant.SUCCESS.equals(returnCode)) {
                String codeUrl = resultMap.get("code_url");
                log.info("微信支付  -扫码支付下单成功,接口返回拼接结果:{}", codeUrl);
                return codeUrl;
            } else {
                log.info("微信支付  -扫码支付下单失败,返回参数:{}", JsonMapper.toJson(resultMap));
                throw new IllegalArgumentException("微信支付  -扫码支付下单失败");
            }
        } else {
            log.info("微信支付  -扫码支付下单失败,返回参数:{}", JsonMapper.toJson(resultMap));
            throw new IllegalArgumentException("微信支付  -扫码支付下单失败");
        }
    }

    /**
     * 微信退款
     * @param orderId 商户订单号
     * @param outTradeNo 商户退款单号
     * @param amount 订单金额
     * @param refundFee 退款金额
     * @param wxPayConfig 微信配置
     * @return
     */
    public String refund(String orderId , String  outTradeNo , String amount , String  refundFee , WxPayConfig wxPayConfig  ) {
        WXPay wxPay = new WXPay(wxPayConfig);
        Map<String, String> resultMap = new HashMap<>(8);
        try {
            Map<String, String> reqData = new HashMap<>();
            reqData.put("out_trade_no", orderId); //商户订单号
            reqData.put("out_refund_no", outTradeNo); //商户退款单号 64
            reqData.put("total_fee", amount + ""); //订单金额
            reqData.put("refund_fee", refundFee + "");//退款金额
            //随机数
            reqData.put("nonce_str", WXPayUtil.generateNonceStr());
            // 应用appId
            reqData.put("appid", wxPayConfig.getAppID());
            // 商户号
            reqData.put("mch_id", wxPayConfig.getMchID());
            //微信签名
            String sign = WXPayUtil.generateSignature(reqData, wxPayConfig.getKey());
            reqData.put("sign", sign);
            //发起退款
            resultMap = wxPay.refund(reqData);

        } catch (Exception e) {
            log.info("退款异常，{}", e.getMessage());
            e.printStackTrace();
            return JsonMapper.toJson(resultMap);
        }

        if (Objects.equals(WxConstant.SUCCESS, resultMap.get("result_code"))
                && Objects.equals(WxConstant.SUCCESS, resultMap.get("return_code"))) {
            return JsonMapper.toJson(resultMap);
        }
        return JsonMapper.toJson(resultMap);
    }

    /**
     * 微信订单查询
     * @param outTradeNo
     * @param transactionId
     * @param wxPayConfig
     * @return
     * @throws Exception
     */
    public Map<String, Object> wxQueryPay(String outTradeNo, String transactionId ,WxPayConfig wxPayConfig){
        try {
            Map<String, Object> returnMap = new LinkedHashMap<>();
            // 处理参数
            WXPay wxPay = new WXPay(wxPayConfig);
            Map<String, String> data = new HashMap<>();
            // 账号ID
            data.put("appid", wxPayConfig.getAppID());
            // 商户号
            data.put("mch_id", wxPayConfig.getMchID());
            // 商户订单编号
            data.put("out_trade_no", outTradeNo);

            if (StringUtils.isNotBlank(transactionId)) {

                data.put("transaction_id", transactionId);
            }
            // 随机字符串
            data.put("nonce_str", WXPayUtil.generateNonceStr());
            // 签名
            String sign = WXPayUtil.generateSignature(data, wxPayConfig.getKey());
            data.put("sign", sign);
            // 发起查询
            Map<String, String> result = wxPay.orderQuery(data);
            if (result.containsKey("result_code")
                    && WxConstant.SUCCESS.equalsIgnoreCase(result.get("result_code"))
                    && result.containsKey("trade_state")
                    && WxConstant.SUCCESS.equalsIgnoreCase(result.get("trade_state"))) {
//                    BigDecimal totalFee = DecimalUtils.fzy(result.get("total_fee"));
                // 查询订单（交易流水的实际金额），判断微信收到的钱和订单中的钱是否等额
                returnMap.put("outTradeNo", result.get("out_trade_no"));
                returnMap.put("tradeNo", result.get("transaction_id"));
                returnMap.put("totalAmount",new BigDecimal(result.get("total_fee")).toString());
                returnMap.put("tradeStatus", result.get("trade_state"));
                return returnMap;
            }

        }catch (Exception e){
            e.printStackTrace();
        }

        return null;
    }

    /**
     *关闭订单
     * @param outTradeNo 内部订单号
     * @param wxPayConfig 微信配置
     * @return true（关闭成功） false（关闭失败）
     * @throws Exception
     */
    public Boolean closeOrderPay(String outTradeNo,  WxPayConfig wxPayConfig) throws Exception {

        WXPay wxPay = new WXPay(wxPayConfig);
        Map<String, String> data = new HashMap<>();
        // 账号ID
//            data.put("appid", wxAppPayConfig.getAppID());
        // 商户号
        data.put("mch_id", wxPayConfig.getMchID());
        // 商户订单编号
        data.put("out_trade_no", outTradeNo);
        // 随机字符串
        data.put("nonce_str", WXPayUtil.generateNonceStr());
        // 签名
        String sign = WXPayUtil.generateSignature(data, wxPayConfig.getKey());
        data.put("sign", sign);
        Map<String, String> result = wxPay.closeOrder(data);
        if (result.containsKey("return_code") && WxConstant.SUCCESS.equalsIgnoreCase(result.get("return_code"))) {
            // 查询订单（交易流水的实际金额），判断微信收到的钱和订单中的钱是否等额
            return true;
        }
        return false;
    }



    private static String sign(String url,String noncestr, Long timeStamp, String ticket) throws Exception {
        String plain = "jsapi_ticket="
                +ticket+"&noncestr="
                +noncestr+"&timestamp="
                +timeStamp+"&url="
                +url;
        log.info("plain:" + plain);
        try {
            MessageDigest sha1 = MessageDigest.getInstance("SHA-1");
            sha1.reset();
            sha1.update(plain.getBytes(StandardCharsets.UTF_8));
            return bytesToHex(sha1.digest());
        } catch (NoSuchAlgorithmException e) {
            // throw new LeysenException("jsapi_ticket计算签名错误");
            throw new Exception("jsapi_ticket计算签名错误");
        }
    }


    public static String genNonce() {
        return bytesToHex(Long.toString(System.nanoTime())
                .getBytes(StandardCharsets.UTF_8));
    }


    public static String bytesToHex(final byte[] hash) {
        Formatter formatter = new Formatter();
        for (byte b : hash) {
            formatter.format("%02x", b);
        }
        String result = formatter.toString();
        formatter.close();
        return result;
    }

    private Map<String, String> requestData(String body, String outTradeNo, String totalFee,
                                            String tradeType , WxPayConfig wxPayConfig) {
        Map<String, String> requestData = new LinkedHashMap<>();

        // 随机签名
        requestData.put("nonce_str", WXPayUtil.generateNonceStr());
        // 商品描述
        requestData.put("body", body);
        // 订单号
        requestData.put("out_trade_no", outTradeNo);
        // 订单金额 微信金额单位为：分 要*100
        requestData.put("total_fee", totalFee);
        // 终端IP
        requestData.put("spbill_create_ip", IpUtils.getHostIp());
        // 微信回调地址
        requestData.put("notify_url", wxPayConfig.getNotifyUrl());
        // 订单生成时间
        requestData.put("time_start", DateUtils.dateTimeNow());
        // 交易类型 JSAPI
        requestData.put("trade_type", tradeType);
        return requestData;
    }
}
